﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
using Com.PhilChuang.Utils;
using Com.PhilChuang.Mobile.Apps.LocationSender.Model.Data;

namespace Com.PhilChuang.Mobile.Apps.LocationSender.Model.Services.Impl
{
	/// <summary>
	/// An implementation of ILocationSenderDao which uses IAppFile
	/// </summary>
	public class LocationSenderDaoDiskImpl : ILocationSenderDao
	{
		#region Constants
		private const String SETTINGS_FILE = "settings.xml";
		private const String RECIPIENTS_FILE = "recipients.txt";
		private const String GEOCOORDINATE_FILE = "geocoordinate.xml";
		private const String GEOCOORDINATE_FORMAT_FILE = "format.txt";
		#endregion

		#region Instance variables
		private readonly IAppFile m_AppFile;
		private readonly XmlSerializer m_GeoCoordinateSerializer;
		private Dictionary<Type, XmlSerializer> m_SettingsSerializers;
		#endregion

		public LocationSenderDaoDiskImpl () : this (AppServiceLocator.Instance.GetImpl<IAppFile> ())
		{
		}

		public LocationSenderDaoDiskImpl (IAppFile appfile)
		{
			m_AppFile = appfile;
			m_GeoCoordinateSerializer = new XmlSerializer (typeof (GeoCoordinate));
			m_SettingsSerializers = new Dictionary<Type, XmlSerializer> ();
			m_SettingsSerializers[typeof (LocationSenderSettings)] = new XmlSerializer (typeof (LocationSenderSettings));
		}

		#region ILocationSenderDao impl
		public void SaveSettings (LocationSenderSettings settings)
		{
			var settingsType = AppServiceLocator.Instance.GetImpl<LocationSenderSettings> ().GetType ();
			if (!m_SettingsSerializers.ContainsKey (settingsType))
				m_SettingsSerializers[settingsType] = new XmlSerializer (settingsType);
			m_AppFile.FileDelete (SETTINGS_FILE);
			m_AppFile.FileCreate (SETTINGS_FILE, stream => m_SettingsSerializers[settingsType].Serialize (stream, settings));
		}

		public void SaveRecipients (IEnumerable<string> recipients)
		{
			m_AppFile.FileDelete (RECIPIENTS_FILE);
			m_AppFile.FileCreate (RECIPIENTS_FILE,
			                      stream => {
			                      	using (var sw = new StreamWriter (stream))
			                      	{
			                      		sw.Write (recipients.Print ("; "));
			                      	}
			                      });
		}

		public void SaveGeoCoordinate (GeoCoordinate gc)
		{
			m_AppFile.FileDelete (GEOCOORDINATE_FILE);
			m_AppFile.FileCreate (GEOCOORDINATE_FILE, stream => m_GeoCoordinateSerializer.Serialize (stream, gc));
		}

		public void SaveGeoCoordinateFormat (GeoCoordinateFormat format)
		{
			m_AppFile.FileDelete (GEOCOORDINATE_FORMAT_FILE);
			m_AppFile.FileCreate (GEOCOORDINATE_FORMAT_FILE,
			                      stream => {
			                      	using (var sw = new StreamWriter (stream))
			                      		sw.Write (format);
			                      });
		}

		
		public LocationSenderSettings LoadSettings ()
		{
			if (!m_AppFile.FileExists (SETTINGS_FILE)) return null;

			var settingsType = AppServiceLocator.Instance.GetImpl<LocationSenderSettings> ().GetType ();
			if (!m_SettingsSerializers.ContainsKey (settingsType))
				m_SettingsSerializers[settingsType] = new XmlSerializer (settingsType);
			LocationSenderSettings result = null;
			m_AppFile.FileOpenRead (SETTINGS_FILE,
									stream =>
									{
										result = (LocationSenderSettings) m_SettingsSerializers[settingsType].Deserialize (stream);
									});
			return result;
		}

		public IEnumerable<string> LoadRecipients ()
		{
			if (!m_AppFile.FileExists (RECIPIENTS_FILE)) return null;
			String recipsStr = null;
			m_AppFile.FileOpenRead (RECIPIENTS_FILE,
			                        stream => {
			                        	using (var sr = new StreamReader (stream))
			                        	{
			                        		recipsStr = sr.ReadToEnd ();
			                        	}
			                        });
			if (recipsStr == null) return null;
			if (recipsStr.IsNullOrEmptyOrBlank ()) return Enumerable.Empty<String> ();
			return recipsStr.Split (';').Select (s => s.Trim ());
		}

		public GeoCoordinate LoadGeoCoordinate ()
		{
			if (!m_AppFile.FileExists (GEOCOORDINATE_FILE)) return null;
			GeoCoordinate result = null;
			m_AppFile.FileOpenRead (GEOCOORDINATE_FILE,
			                        stream => {
			                        	result = (GeoCoordinate) m_GeoCoordinateSerializer.Deserialize (stream);
			                        });
			return result;
		}

		public GeoCoordinateFormat LoadGeoCoordinateFormat ()
		{
			if (!m_AppFile.FileExists (GEOCOORDINATE_FORMAT_FILE)) return GeoCoordinateFormat.None;
			GeoCoordinateFormat result = GeoCoordinateFormat.None;
			m_AppFile.FileOpenRead (GEOCOORDINATE_FORMAT_FILE,
			                        stream => {
			                        	using (var sr = new StreamReader (stream))
			                        	{
			                        		Extensions.EnumTryParse (sr.ReadToEnd (), ref result);
			                        	}
			                        });
			return result;
		}
		#endregion
	}
}
